﻿#ifndef __SS_3dMATH_FUNC_H__
#define __SS_3dMATH_FUNC_H__
#include "ssMatrix.h"
#include "ssVector.h"
#include "ssVector2.h"
#include "ssQuaternion.h"

//https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixortholh
//所有的矩阵都是行矩阵，变换都是右乘，和DX一致，用于opengl要注意
//行矩阵和列矩阵互为转置矩阵
//DX和opengl的矩阵在内存中(一维数组)存贮的数据是一样的，一个是按行一个是按列，从一维的角度来看是一样的
//把矩阵传入GLSL中后矩阵的运算要按列矩阵左乘的规则来算
namespace StarSeeker
{
namespace Math3D
{

//快速计算平方根倒数，1/√(x)，近似值不是精确值
float FastRsqrt(float num);

//两点距离
ssfloat TwoPositionDistance3(ssfloat fP1x, ssfloat fP1y, ssfloat fP1z, ssfloat fP2x, ssfloat fP2y, ssfloat fP2z);
ssfloat TwoPositionDistance2(ssfloat fP1x, ssfloat fP1y, ssfloat fP2x, ssfloat fP2y);

//向量点乘
ssfloat Float3XDot(const ssFLOAT3 *pIn1, const ssFLOAT3 *pIn2);
//向量夹角
ssfloat Float3XIncludedAngle(const ssFLOAT3X *pIn1, const ssFLOAT3X *pIn2);
ssfloat Float3XNormalizeIncludedAngle(const ssFLOAT3X *pIn1, const ssFLOAT3X *pIn2);
ssfloat Float2XIncludedAngle(const ssFLOAT2X *pIn1, const ssFLOAT2X *pIn2);
ssfloat Float2XNormalizeIncludedAngle(const ssFLOAT2X *pIn1, const ssFLOAT2X *pIn2);

//向量叉乘
void Float3XCross(ssFLOAT3 *pOut, const ssFLOAT3 *pIn1, const ssFLOAT3 *pIn2);
void Float3XNormalCross(ssFLOAT3X *pOut, ssFLOAT3X *pIn1, ssFLOAT3X *pIn2);

//矩阵乘法
void FLOAT4x4XMultiply(ssFLOAT4x4 *pOut, const ssFLOAT4x4 *pIn1, const ssFLOAT4x4 *pIn2);

//坐标乘矩阵
void FLOAT4x4XTransformCoord(ssFLOAT3X *pOut, const ssFLOAT4x4X *pIn1, const ssFLOAT3X *pIn2);

//向量乘矩阵,行向量右乘矩阵
void FLOAT4x4XTransformVector3(ssFLOAT3X *pOut, const ssFLOAT4x4X *pIn1, const ssFLOAT3X *pIn2);
void FLOAT3x3XTransformVector3(ssFLOAT3X *pOut, const ssFLOAT3x3X *pIn1, const ssFLOAT3X *pIn2);
void FLOAT4x4XTransformVector4(ssFLOAT4X *pOut, const ssFLOAT4x4X *pIn1, const ssFLOAT4X *pIn2);

//绕X轴旋转的矩阵
void FLOAT4x4XRotX(ssFLOAT4x4X *pIn, ssfloat angle);
void FLOAT3x3XRotX(ssFLOAT3x3X *pIn, ssfloat angle);

//绕Y轴旋转的矩阵
void FLOAT4x4XRotY(ssFLOAT4x4X *pOut, ssfloat angle);
void FLOAT3x3XRotY(ssFLOAT3x3X *pOut, ssfloat angle);

//绕Z轴旋转的矩阵
void FLOAT4x4XRotZ(ssFLOAT4x4X *pOut, ssfloat angle);
void FLOAT3x3XRotZ(ssFLOAT3x3X *pOut, ssfloat angle);

//绕任意轴旋转
void FLOAT4x4XRotation(ssFLOAT4x4X *pOut, ssfloat angle, ssFLOAT3X *pAxis);
void FLOAT3x3XRotation(ssFLOAT3x3X *pOut, ssfloat angle, ssFLOAT3X *pAxis);
void FLOAT4x4XRotationForColumnMatrix(ssFLOAT4x4X *pOut, ssfloat angle, ssFLOAT3X *pAxis);

//缩放矩阵
void FLOAT4x4XScaling(ssFLOAT4x4X *pOut, ssfloat xAxis, ssfloat yAxis, ssfloat zAxis);
void FLOAT3x3XScaling(ssFLOAT3x3X *pOut, ssfloat xAxis, ssfloat yAxis, ssfloat zAxis);

//判断点在线段内
bool PointIsOnLine(const ssFLOAT3X *pa, const ssFLOAT3X *pb, const ssFLOAT3X *po);

//判断点在三角形内
bool PointIsOnTriangle(const ssFLOAT3X *pa, const ssFLOAT3X *pb, const ssFLOAT3X *pc, const ssFLOAT3X *po);

//求面法线
void GetFaceNormal(ssFLOAT3X *pOut, const ssFLOAT3X *pa, const ssFLOAT3X *pb, const ssFLOAT3X *pc);

//判断点在4面体内
bool PointIsInTetrahedron(const ssFLOAT3X *pa, const ssFLOAT3X *pb, const ssFLOAT3X *pc, const ssFLOAT3X *pd, const ssFLOAT3X *po);

//透视投影
ssFLOAT4x4X PerspectiveRH(const ssfloat width, const ssfloat hight, const ssfloat zNear, const ssfloat zFar);
ssFLOAT4x4X PerspectiveOffCenterRH(const ssfloat left, const ssfloat right, const ssfloat bottom, const ssfloat top, const ssfloat zNear, const ssfloat zFar);
ssFLOAT4x4X PerspectiveFovRH(const ssfloat fovy, const ssfloat aspect, const ssfloat zNear, const ssfloat zFar);
ssFLOAT4x4X PerspectiveLH(const ssfloat width, const ssfloat hight, const ssfloat zNear, const ssfloat zFar);
ssFLOAT4x4X PerspectiveOffCenterLH(const ssfloat left, const ssfloat right, const ssfloat bottom, const ssfloat top, const ssfloat zNear, const ssfloat zFar);

//正交投影
ssFLOAT4x4X OrthoRH(const ssfloat width, const ssfloat hight, const ssfloat zNear, const ssfloat zFar);
ssFLOAT4x4X OrthoOffCenterRH(const ssfloat left, const ssfloat right, const ssfloat bottom, const ssfloat top, const ssfloat zNear, const ssfloat zFar);
ssFLOAT4x4X OrthoLH(const ssfloat width, const ssfloat hight, const ssfloat zNear, const ssfloat zFar);
ssFLOAT4x4X OrthoOffCenterLH(const ssfloat left, const ssfloat right, const ssfloat bottom, const ssfloat top, const ssfloat zNear, const ssfloat zFar);

//浮点数插值
ssfloat FloatLerp(ssfloat a, ssfloat b, ssfloat per);

//向量插值
void VectorLerp(ssFLOAT3X *pOut, ssFLOAT3X *pIn1, ssFLOAT3X *pIn2, ssfloat per);

//四元数转矩阵
void QuaternionToMatrix3x3(ssFLOAT4X *pQ, ssFLOAT3x3X *pM);
void QuaternionToMatrix4x4(ssFLOAT4X *pQ, ssFLOAT4x4X *pM);
//矩阵转四元数
void Matrix3x3ToQuaternion(ssFLOAT3x3X *pM, ssFLOAT4X *pQ);
//向量乘四元数,行向量右乘四元数
void FLOAT4XTransformNormal(ssFLOAT3X *pOut, const ssFLOAT4X *pQ, ssFLOAT3X *pV);

//判断射线与平面相交
//n平面法线，p1平面上的点，p0射线起点，d射线方向
//交点为p0+td
bool RayIntersectsPlane(ssFLOAT3X& n, ssFLOAT3X& p1, ssFLOAT3X& p0, ssFLOAT3X& d, ssFLOAT3X* intersection=0);

//屏幕坐标转世界坐标
bool ScreenToWorld(const ssFLOAT3X *pInCoord, const ssFLOAT4x4X *pInView, const ssFLOAT4x4X *pInProjection, const ssViewPort *pInViewPort, ssFLOAT3X *pOut);
//世界坐标转屏幕坐标
bool WorldToScreen(const ssFLOAT3X *pInCoord, const ssFLOAT4x4X *pInView, const ssFLOAT4x4X *pInProjection, const ssViewPort *pInViewPort, ssFLOAT3X *pOut);

//将一个向量分解到直角坐标系的三个轴上，三个轴由三个互相垂直的单位向量表示
void DecomposingVectorIntoCoordinateSystems(const ssFLOAT3X& in, const ssFLOAT3X& axis1, const ssFLOAT3X& axis2, const ssFLOAT3X& axis3, ssFLOAT3X& out1, ssFLOAT3X& out2, ssFLOAT3X& out3);

//点到线的距离平方,输入参数：点坐标、线起点、线单位向量
ssfloat Point2LineDistance(const ssFLOAT3X& m, const ssFLOAT3X& begin, const ssFLOAT3X& dir);
ssfloat Point2LineDistance2D(const ssFLOAT2X& m, const ssFLOAT2X& begin, const ssFLOAT2X& dir);
//点在线上的投影
ssFLOAT3X Point2LineProjection(const ssFLOAT3X& m, const ssFLOAT3X& begin, const ssFLOAT3X& dir);
ssFLOAT2X Point2LineProjection2D(const ssFLOAT2X& m, const ssFLOAT2X& begin, const ssFLOAT2X& dir);

//二维向量旋转(点旋转)
ssFLOAT2X Rotate2dVector(const ssFLOAT2X& v, ssfloat radian);

//顺时针二维坐标旋转,输入参数：点坐标、以正Y轴为起点的旋转后单位向量
ssFLOAT2X CoordRotation2D(const ssFLOAT2X& p, const ssFLOAT2X& dir);

//线段与圆是否相交,输入参数：圆心、半径、线起点、线向量
bool LineIntersectsCircle(const ssFLOAT2X& center, ssfloat r, const ssFLOAT2X& lineBegin, const ssFLOAT2X& lineDir);

//点是否在线段的中间(点要在线段上)
bool PointInTheMiddleOfTheLine(const ssFLOAT3X& lineBegin, const ssFLOAT3X& lineEnd, const ssFLOAT3X& p);
bool PointInTheMiddleOfTheLine2D(const ssFLOAT2X& lineBegin, const ssFLOAT2X& lineEnd, const ssFLOAT2X& p);

}
}
#endif
